﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;

using Bling.Core;
using Bling.WPF;
using Bling.WPF.Custom;
using Bling.WPF.Util;
using Bling.Slides;
using Bling.Util;
using Bling.Shaders;
using Bling.Graphics;
using Bling.Angles;
namespace Bling.Example {
  using Bling.Matrices;
  using Bling.WPF3D;
  using Bling.DX;

  public class Bump : HasDX10Canvas {

    public Bump() : base(false) {
      var Uri = new Uri[] {
      "Resources/dock1.jpg".MakePackUri(typeof(Bump)),
      "Resources/4336-normal.jpg".MakePackUri(typeof(Bump)),
      "Resources/243-diffuse.jpg".MakePackUri(typeof(Bump)),
      "Resources/243-normal.jpg".MakePackUri(typeof(Bump)),
      "Resources/890-diffuse.jpg".MakePackUri(typeof(Bump)),
      "Resources/890-normal.jpg".MakePackUri(typeof(Bump)),
      "Resources/Set_floo.jpg".MakePackUri(typeof(Bump)),
      "Resources/Set_floo_NRM.png".MakePackUri(typeof(Bump)),
      "Resources/1146-diffuse.jpg".MakePackUri(typeof(Bump)),
      "Resources/1146-normal.jpg".MakePackUri(typeof(Bump)),
      };

      var changeMaterial = new ComboBoxBl(this) { LeftTop = new Double2Bl(550, 0), SelectedIndex = 1 };
      changeMaterial.Items.Add(new ComboBoxItem() { Content = "misc Pic" });
      changeMaterial.Items.Add(new ComboBoxItem() { Content = "Decorative Tiles" });
      changeMaterial.Items.Add(new ComboBoxItem() { Content = "Bumped metal" });
      changeMaterial.Items.Add(new ComboBoxItem() { Content = "Rock" });
      changeMaterial.Items.Add(new ComboBoxItem() { Content = "Panels" });

      Host.LeftTop = 0d; Host.Size = 550;
      var sliderX = new LabelSliderBl(this) {
        LabelName = "X",
        ZIndex = 100,
      };
      var sliderY = new LabelSliderBl(this) {
        LabelName = "Y",
        ZIndex = 100,
        LeftTop = sliderX.LeftBottom,
      };
      var sliderZ = new LabelSliderBl(this) {
        LabelName = "Z",
        ZIndex = 100,
        LeftTop = sliderY.LeftBottom,
      };
      var sliderS = new LabelSliderBl(this) {
        LabelName = "Scale",
        ZIndex = 100,
        LeftTop = sliderZ.LeftBottom,
        Minimum = 1, Maximum = 6, Value = 2
      };
      Matrix4Bl World = sliderX.Value.PI2.RotateAround(new Double3Bl(1d, 1d, sliderZ).Normalize).Matrix;
      World = World * sliderY.Value.PI2.RotateAround(new Double3Bl(sliderZ, 1d, 1d).Normalize);

      var eye = new Double3Bl(0f, -1.5d, -3d);
      var at = new Double3Bl(0f, 0f, 0f);
      var up = new Double3Bl(0f, 1f, 0f);

      PerspectiveCameraCl Camera = new PerspectiveCameraCl() {
        Position = eye,
        Direction = { Look = at, Up = up },
        FieldOfView = .25.PI().Degrees,
      };


      //var view = eye.LookAt(at, up);
      //var project = (.25.PI()).PerspectiveFov(550d / 550d, .1, 100d);
      var ambLight = new AmbientLightBl() { Color = Colors.White.Bl() };
      var dirLight = new DirectionalLightBl() {
        Direction = new Double3Bl(1, 0, 0).Normalize,
        Color = Colors.White.Bl(),
      };

      var diffMaterial = new DiffuseMaterialCl() { Ambient = { Knob = 0.3 },  };
      var specMaterial = new SpecularMaterialCl(){ Power = 2, Knob = 0.7};

      var Surface = GraphicDefinitions.Sphere.Displace((GraphicDefinitions.EggCrate.Adjust(5d, .05d, 0)));
      //var SurfaceKeys = new PSurfaceSample(200, 200);

      var textures = new Texture2Bl[] {
        new ImageTexture<D2>(Uri[0]),
        new ImageTexture<D2>(Uri[2]),
        new ImageTexture<D2>(Uri[4]),
        new ImageTexture<D2>(Uri[6]),
        new ImageTexture<D2>(Uri[8]),
      };
      var normals = new Texture2Bl[] {
        new ImageTexture<D2>(Uri[1]),
        new ImageTexture<D2>(Uri[3]),
        new ImageTexture<D2>(Uri[5]),
        new ImageTexture<D2>(Uri[7]),
        new ImageTexture<D2>(Uri[9]),
      };

      var Texture = textures.Table(changeMaterial.SelectedIndex);
      var Normal  = normals .Table(changeMaterial.SelectedIndex);


      Device.Render(Surface[100,100], (Entry, vertex) => {
        //different parameter surface seems need different way to load texture
        var uv0 = Entry.Texture.YX() * new Double2Bl(1,2) * sliderS.Value % 1;
        //var uv0 = new Double2Bl(uv.Y +0.5, (uv.X + 0.5)*2) * sliderS.Value % 1;
        vertex.Position = (Camera.Matrix * World).Transform(Entry.Position); //[uv]; ;
        var usePosition = World.Transform(Entry.Position);

        //compute the matrix that can transform from tangent space(where normal map is in) to object space(where 3d point is in)
        var N = World.Transform(Entry.Normal).Normalize;
        var T = World.Transform(Entry.Tangent).Normalize;
        var B = N.Cross(T).Normalize;
        Matrix3Bl TBN = Matrix3Bl.ByRows(T, B, N); 
 
        //transform the normal from tangent space to object space to inplement bump mapping, or we can transform
        //light source and eye position to tangent space, they are the same, just make sure all the value is in the same space
        var norm = (Double3Bl)(Normal[uv0].XYZ() * 2 - 1).Normalize;
        Double3Bl useNorm = (norm.Transpose * TBN).Transpose;

        Lighting L = (diffMaterial + specMaterial).ApplyLights(dirLight + ambLight);
        vertex.Color = L.ApplyAt(usePosition.PerPixel(), useNorm.PerPixel()).ForPixel(Texture, uv0);
      });
      sliderX.LeftTop = Host.LeftBottom;
    }
  }
}
